// 错误处理
// 自定义错误

// 创建错误
// package main

// import (
// 	"errors"
// 	"fmt"
// )

// func main() {
// 	err := errors.New("this is an error")
// 	var err2 error
// 	fmt.Println(err.Error())
// 	fmt.Println(err2)

// }

// 自定义错误格式
// package main

// import (
// 	"fmt"
// 	"runtime"
// )

// func main() {
// 	if _, _, line, ok := runtime.Caller(0); ok == true {
// 		err := fmt.Errorf("***Line %d error***", line)
// 		fmt.Println(err.Error())
// 	}
// }

// go 宕机 调用panic， 程序的执行将直接中断
// package main

// import "fmt"

// func main() {
// 	panic("Serious bug")
// 	fmt.Println("invalid code")
// }
// 宕机恢复
// 宕机捕获
// func protect() {
// 	defer func() {
// 		fmt.Println("func protect exit")
// 	}()
// 	panic("Serious bug")
// }

// func main() {
// 	defer func() {
// 		fmt.Println("func main exit")
// 	}()
// 	protect()
// 	fmt.Println("Invalid code")
// }

// func protect() {
// 	defer func() {
// 		if err := recover(); err != nil {
// 			fmt.Println(err)
// 		}
// 		fmt.Println("test")
// 	}()
// 	panic("Serious bug")
// }

// func main() {
// 	protect()
// 	fmt.Println("valid code")
// }

// recover 应用
// func protect(f func()) {
// 	defer func() {
// 		if err := recover(); err != nil {
// 			fmt.Println(err)
// 		}
// 	}()
// 	f()
// }

// func main() {
// 	protect(func() {
// 		fmt.Println("This is function 1")
// 		panic("Serious bug from function1")
// 	})
// 	protect(func() {
// 		fmt.Println("This is function 2")
// 		panic("Serious bug from function2")
// 	})
// 	fmt.Println("valid code")
// }

// package main

// import (
// 	"errors"
// 	"fmt"
// )

// func div(dividend int, divisor int) (int, error) {
// 	if divisor == 0 {
// 		return 0, errors.New("divisor is zero")
// 	}
// 	return dividend / divisor, nil
// }

// func main() {
// 	res1, err := div(4, 2)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	} else {
// 		fmt.Println("4/2 =", res1)
// 	}
// 	res2, err := div(1, 0)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	} else {
// 		fmt.Println("1/0 =", res2)
// 	}
// }

// go语言中使用多值返回错误
// go error类型实际上为一个接口， error接口包含Error方法， 用来返回一个字符串
// 标准库 error 可以用来创建错误， 自定义错误

// 自定义一个类型 并实现Error方法
package main

import (
	"fmt"
	"math"
)

type ErrNeqSqrt float64

func (e ErrNeqSqrt) Error() string {
	return fmt.Sprintf("cannot Sqrt negative number: %v", float64(e))
}

func sqrt(x float64) (float64, error) {
	if x < 0.0 {
		return 0, ErrNeqSqrt(x)
	} else {
		return math.Sqrt(x), nil
	}
}

func main() {
	res, err := sqrt(-2)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(res)
	}
}
